home *** CD-ROM | disk | FTP | other *** search
- ;; Copyright (C) 1994 M. Hagiya, W. Schelter, T. Yuasa
-
- ;; This file is part of GNU Common Lisp, herein referred to as GCL
- ;;
- ;; GCL is free software; you can redistribute it and/or modify it under
- ;; the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE as published by
- ;; the Free Software Foundation; either version 2, or (at your option)
- ;; any later version.
- ;;
- ;; GCL is distributed in the hope that it will be useful, but WITHOUT
- ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
- ;; License for more details.
- ;;
- ;; You should have received a copy of the GNU Library General Public License
- ;; along with GCL; see the file COPYING. If not, write to the Free Software
- ;; Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
- ;;;; top.lsp
- ;;;;
- ;;;; Top-level loop, break loop, and error handlers
- ;;;;
- ;;;; Revised on July 11, by Carl Hoffman.
-
-
- (in-package 'lisp)
-
- (export '(+ ++ +++ - * ** *** / // ///))
- (export '(break warn))
- (export '*break-on-warnings*)
- (export '*break-enable*)
-
- (in-package 'system)
-
- (export '*break-readtable*)
- (export '(loc *debug-print-level*))
-
- (export '(vs ihs-vs ihs-fun frs-vs frs-bds frs-ihs bds-var bds-val super-go))
-
- (eval-when (compile) (proclaim '(optimize (safety 2) (space 3))))
- (defvar *command-args* nil)
- (defvar +)
- (defvar ++)
- (defvar +++)
- (defvar -)
- (defvar *)
- (defvar **)
- (defvar ***)
- (defvar /)
- (defvar //)
- (defvar ///)
-
- (defvar *lisp-initialized* nil)
-
- (defvar *quit-tag* (cons nil nil))
- (defvar *quit-tags* nil)
- (defvar *break-level* '())
- (defvar *break-env* nil)
- (defvar *ihs-base* 1)
- (defvar *ihs-top* 1)
- (defvar *current-ihs* 1)
- (defvar *frs-base* 0)
- (defvar *frs-top* 0)
- (defvar *break-enable* t)
- (defvar *break-message* "")
-
- (defvar *break-on-warnings* nil)
-
- (defvar *break-readtable* nil)
-
- (defvar *top-level-hook* nil)
-
- (defvar *top-eof* (cons nil nil))
- (defvar *no-prompt* nil)
- (defun top-level ()
- (let ((+ nil) (++ nil) (+++ nil)
- (- nil)
- (* nil) (** nil) (*** nil)
- (/ nil) (// nil) (/// nil))
- (setq *lisp-initialized* t)
- (catch *quit-tag*
- (let ((tem (string-concatenate *system-directory*
- "sys-init.lsp")))
- (when (probe-file tem)
- (load tem :verbose nil))
- (cond (*multiply-stacks* (setq *multiply-stacks* nil))
- ((probe-file "init.lsp") (load "init.lsp")))
- (loop (setq tem *command-args*)
- (cond ((setq tem (member "-load" tem :test 'equal))
- (load (second tem) :verbose nil)
- (setq tem (cddr tem))))
- (or tem (return nil))))
- (and (functionp *top-level-hook*)(funcall *top-level-hook*)))
-
- (loop
- (setq +++ ++ ++ + + -)
- (if *no-prompt* (setq *no-prompt* nil)
- (format t "~%~a>"
- (if (eq *package* (find-package 'user)) ""
- (package-name *package*))))
- (reset-stack-limits)
- ;; have to exit and re-enter to multiply stacks
- (cond (*multiply-stacks* (Return-from top-level)))
- (when (catch *quit-tag*
- (setq - (locally (declare (notinline read))
- (read *standard-input* nil *top-eof*)))
- (when (eq - *top-eof*) (bye))
- (let ((values (multiple-value-list
- (locally (declare (notinline eval)) (eval -)))))
- (setq /// // // / / values *** ** ** * * (car /))
- (fresh-line)
- (dolist (val /)
- (locally (declare (notinline prin1)) (prin1 val))
- (terpri))
- nil))
- (setq *evalhook* nil *applyhook* nil)
- (terpri *error-output*)
- (break-current)))))
-
-
- (defun dbl-read (&optional (stream *standard-input*) (eof-error-p t)
- (eof-value nil) &aux tem ch)
- (tagbody
- top
- (setq ch (read-char stream eof-error-p eof-value))
- (cond ((eql ch #\newline) (go top))
- ((eq ch eof-value) (return-from dbl-read eof-value)))
- (unread-char ch stream))
-
- (cond ((eql #\: ch)
- (setq tem
- (string-concatenate
- "("
- (read-line stream eof-error-p eof-value)")"))
- (read (make-string-input-stream tem)
- eof-error-p eof-value))
- (t (read stream eof-error-p eof-value))))
-
-
- (defun break-level (at &optional env)
- (let* ((*break-message* (if (stringp at) at *break-message*))
- (*quit-tags* (cons (cons *break-level* *quit-tag*) *quit-tags*))
- (*quit-tag* (cons nil nil))
- (*break-level* (if (not at) *break-level* (cons t *break-level*)))
- (*ihs-base* (1+ *ihs-top*))
- (*ihs-top* (1- (ihs-top)))
- (*current-ihs* *ihs-top*)
- (*frs-base* (or (sch-frs-base *frs-top* *ihs-base*) (1+ (frs-top))))
- (*frs-top* (frs-top))
- (*break-env* nil)
- (be *break-enable*)
- (*break-enable*
- (progn
- (if (stringp at) nil be)))
- ;(*standard-input* *terminal-io*)
- (*readtable* (or *break-readtable* *readtable*))
- (*read-suppress* nil)
- (+ +) (++ ++) (+++ +++)
- (- -)
- (* *) (** **) (*** ***)
- (/ /) (// //) (/// ///)
- )
- ; (terpri *error-output*)
- (unless (or be (not (stringp at)))
- (simple-backtrace)
- (break-quit (length (cdr *break-level*))))
- (catch-fatal 1)
- (setq *interrupt-enable* t)
- (cond ((stringp at) (set-current)(terpri *error-output*)
- (setq *no-prompt* nil)
- )
- (t (set-back at env)))
- (loop
- (setq +++ ++ ++ + + -)
- (cond (*no-prompt* (setq *no-prompt* nil))
- (t
- (format *debug-io* "~&~a~a>~{~*>~}"
- (if (stringp at) "" "dbl:")
- (if (eq *package* (find-package 'user)) ""
- (package-name *package*))
- *break-level*)))
- (when
- (catch 'step-continue
- (catch *quit-tag*
- (setq - (locally (declare (notinline read))
- (dbl-read *debug-io* nil *top-eof*)))
- (when (eq - *top-eof*) (bye))
- (let* ( break-command
- (values
- (multiple-value-list
- (LOCALLY (declare (notinline break-call evalhook))
- (if (keywordp -)(setq - (cons - nil)))
- (cond ((and (consp -) (keywordp (car -)))
- (setq break-command t)
- (break-call (car -) (cdr -)))
- (t (evalhook - nil nil *break-env*)))))))
- (and break-command (eq (car values) :resume )(return))
- (setq /// // // / / values *** ** ** * * (car /))
- (fresh-line *debug-io*)
- (dolist (val /)
- (locally (declare (notinline prin1)) (prin1 val *debug-io*))
- (terpri *debug-io*)))
- nil))
- (terpri *debug-io*)
- (break-current))))))
-
- (defvar *debug-print-level* 3)
-
- (defun warn (format-string &rest args)
- (let ((*print-level* 4)
- (*print-length* 4)
- (*print-case* :upcase))
- (cond (*break-on-warnings*
- (apply #'break format-string args))
- (t (format *error-output* "~&Warning: ")
- (let ((*indent-formatted-output* t))
- (apply #'format *error-output* format-string args))
- nil))))
-
- (defun universal-error-handler
- (error-name correctable function-name
- continue-format-string error-format-string
- &rest args &aux message)
- (declare (ignore error-name))
- (let ((*print-pretty* nil)
- (*print-level* *debug-print-level*)
- (*print-length* *debug-print-level*)
- (*print-case* :upcase))
- (terpri *error-output*)
- (cond ((and correctable *break-enable*)
- (format *error-output* "~&Correctable error: ")
- (let ((*indent-formatted-output* t))
- (apply 'format *error-output* error-format-string args))
- (terpri *error-output*)
- (setq message (apply 'format nil error-format-string args))
- (if function-name
- (format *error-output*
- "Signalled by ~:@(~S~).~%" function-name)
- (format *error-output*
- "Signalled by an anonymous function.~%"))
- (format *error-output* "~&If continued: ")
- (let ((*indent-formatted-output* t))
- (format *error-output* "~?~&" continue-format-string args))
- )
- (t
- (format *error-output* "~&Error: ")
- (let ((*indent-formatted-output* t))
- (apply 'format *error-output* error-format-string args))
- (terpri *error-output*)
- (if (> (length *link-array*) 0)
- (format *error-output* "Fast links are on: do (use-fast-links nil) for debugging~%"))
- (setq message (apply 'format nil error-format-string args))
- (if function-name
- (format *error-output*
- "Error signalled by ~:@(~S~).~%" function-name)
- (format *error-output*
- "Error signalled by an anonymous function.~%")))))
- (break-level message)
- (unless correctable (throw *quit-tag* *quit-tag*)))
-
- (defun break (&optional format-string &rest args &aux message)
- (let ((*print-pretty* nil)
- (*print-level* 4)
- (*print-length* 4)
- (*print-case* :upcase))
- (terpri *error-output*)
- (cond (format-string
- (format *error-output* "~&Break: ")
- (let ((*indent-formatted-output* t))
- (apply 'format *error-output* format-string args))
- (terpri *error-output*)
- (setq message (apply 'format nil format-string args)))
- (t (format *error-output* "~&Break.~%")
- (setq message ""))))
- (let ((*break-enable* t)) (break-level message))
- nil)
-
- (defun terminal-interrupt (correctablep)
- (let ((*break-enable* t))
- (if correctablep
- (cerror "Type :r to resume execution, or :q to quit to top level."
- "Console interrupt.")
- (error "Console interrupt -- cannot continue."))))
-
-
- (defun break-call (key args &aux (fun (get key 'break-command)))
- (if fun
- (evalhook (cons fun args) nil nil *break-env*)
- (format *debug-io* "~&~S is undefined break command.~%" key)))
-
- (defun break-quit (&optional (level 0)
- &aux (current-level (length *break-level*)))
- (when (and (>= level 0) (< level current-level))
- (let ((x (nth (- current-level level 1) *quit-tags*)))
- (throw (cdr x) (cdr x))))
- (break-current))
-
- (defun break-previous (&optional (offset 1))
- (do ((i (1- *current-ihs*) (1- i)))
- ((or (< i *ihs-base*) (<= offset 0))
- (set-env)
- (break-current))
- (when (ihs-visible i)
- (setq *current-ihs* i)
- (setq offset (1- offset)))))
-
- (defun set-current ()
- (do ((i *current-ihs* (1- i)))
- ((or (ihs-visible i) (<= i *ihs-base*))
- (setq *current-ihs* i)
- (set-env)
- (format *debug-io* "Broken at ~:@(~S~).~:[ Type :H for Help.~;~]"
- (ihs-fname *current-ihs*)
- (cdr *break-level*)))))
-
- (defun break-next (&optional (offset 1))
- (do ((i *current-ihs* (1+ i)))
- ((or (> i *ihs-top*) (< offset 0))
- (set-env)
- (break-current))
- (when (ihs-visible i)
- (setq *current-ihs* i)
- (setq offset (1- offset)))))
-
- (defun break-go (ihs-index)
- (setq *current-ihs* (min (max ihs-index *ihs-base*) *ihs-top*))
- (if (ihs-visible *current-ihs*)
- (progn (set-env) (break-current))
- (break-previous)))
-
- (defun break-message ()
- (princ *break-message* *debug-io*)
- (terpri *debug-io*)
- (values))
-
- (defun describe-environment (&optional (env *break-env*) (str *debug-io*))
- (or (eql (length env) 3) (error "bad env"))
- (let ((fmt "~a~#[none~;~S~;~S and ~S~
- ~:;~@{~#[~;and ~]~S~^, ~}~].~%"))
- (apply 'format str fmt "Local variables: "
- (mapcar #'car (car *break-env*)))
- (apply 'format str fmt "Local functions: "
- (mapcar #'car (cadr *break-env*)))
- (apply 'format str fmt "Local blocks: "
- (mapcan #'(lambda (x) (when (eq (cadr x) 'block) (list (car x))))
- (caddr *break-env*)))
- (apply 'format str fmt "Local tags: "
- (mapcan #'(lambda (x) (when (eq (cadr x) 'tag) (list (car x))))
- (caddr *break-env*)))))
-
- (defun break-vs (&optional (x (ihs-vs *ihs-base*)) (y (ihs-vs *ihs-top*)))
- (setq x (max x (ihs-vs *ihs-base*)))
- (setq y (min y (1- (ihs-vs (1+ *ihs-top*)))))
- (do ((ii *ihs-base* (1+ ii)))
- ((or (>= ii *ihs-top*) (>= (ihs-vs ii) x))
- (do ((vi x (1+ vi)))
- ((> vi y) (values))
- (do ()
- ((> (ihs-vs ii) vi))
- (when (ihs-visible ii) (print-ihs ii))
- (incf ii))
- (format *debug-io* "~&VS[~d]: ~s" vi (vs vi))))))
-
- (defun break-local (&optional (n 0) &aux (x (+ (ihs-vs *current-ihs*) n)))
- (break-vs x x))
-
- (defun break-bds (&rest vars &aux (fi *frs-base*))
- (do ((bi (1+ (frs-bds (1- *frs-base*))) (1+ bi))
- (last (frs-bds (1+ *frs-top*))))
- ((> bi last) (values))
- (when (or (null vars) (member (bds-var bi) vars))
- (do ()
- ((or (> fi *frs-top*) (> (frs-bds fi) bi)))
- (print-frs fi)
- (incf fi))
- (format *debug-io* "~&BDS[~d]: ~s = ~s"
- bi (bds-var bi) (bds-val bi)))))
-
- (defun simple-backtrace ()
- (princ "Backtrace: " *debug-io*)
- (do* ((i *ihs-base* (1+ i))
- (b nil t))
- ((> i *ihs-top*) (terpri *debug-io*) (values))
- (when (ihs-visible i)
- (when b (princ " > " *debug-io*))
- (write (ihs-fname i) :stream *debug-io* :escape t
- :case (if (= i *current-ihs*) :upcase :downcase)))))
-
- (defun ihs-backtrace (&optional (from *ihs-base*) (to *ihs-top*))
- (setq from (max from *ihs-base*))
- (setq to (min to *ihs-top*))
- (do* ((i from (1+ i))
- (j (or (sch-frs-base *frs-base* from) (1+ *frs-top*))))
- ((> i to) (values))
- (when (ihs-visible i) (print-ihs i))
- (do () ((or (> j *frs-top*) (> (frs-ihs j) i)))
- (print-frs j)
- (incf j))))
-
- (defun print-ihs (i &aux (*print-level* 2) (*print-length* 4))
- (format t "~&~:[ ~;@ ~]IHS[~d]: ~s ---> VS[~d]"
- (= i *current-ihs*)
- i
- (let ((fun (ihs-fun i)))
- (cond ((or (symbolp fun) (compiled-function-p fun)) fun)
- ((consp fun)
- (case (car fun)
- (lambda fun)
- ((lambda-block lambda-block-expanded) (cdr fun))
- (lambda-closure (cons 'lambda (cddddr fun)))
- (lambda-block-closure (cddddr fun))
- (t (cond
- ((and (symbolp (car fun))
- (or (special-form-p(car fun))
- (fboundp (car fun))))
- (car fun))
- (t '(:zombi))))))
- (t (print fun)
- :zombi)))
- (ihs-vs i)))
-
- (defun print-frs (i)
- (format *debug-io* "~& FRS[~d]: ~s ---> IHS[~d],VS[~d],BDS[~d]"
- i (frs-kind i) (frs-ihs i) (frs-vs i) (frs-bds i)))
-
- (defun frs-kind (i &aux x)
- (case (frs-class i)
- (:catch
- (if (spicep (frs-tag i))
- (or (and (setq x (member (frs-tag i) (vs (+ (frs-vs i) 2))
- :key #'caddr :test #'eq))
- (if (eq (cadar x) 'block)
- `(block ,(caar x) ***)
- `(tagbody ,@(reverse (mapcar #'car
- (remove (frs-tag i) x
- :test-not #'eq
- :key #'caddr)))
- ***)))
- `(block/tagbody ,(frs-tag i)))
- `(catch ',(frs-tag i) ***)))
- (:protect '(unwind-protect ***))
- (t `(system-internal-catcher ,(frs-tag i)))))
-
- (defun break-current ()
- (if *break-level*
- (format *debug-io* "Broken at ~:@(~S~)." (ihs-fname *current-ihs*))
- (format *debug-io* "~&Top level."))
- (values))
-
-
-
- (defvar *break-hidden-packages* nil)
-
- (defun ihs-visible (i &aux (tem (ihs-fname i)))
- (and tem (not (member tem *break-hidden-packages*))))
-
-
- (defun ihs-fname (ihs-index)
- (let ((fun (ihs-fun ihs-index)))
- (cond ((symbolp fun) fun)
- ((consp fun)
- (case (car fun)
- (lambda 'lambda)
- ((lambda-block lambda-block-expanded) (cadr fun))
- (lambda-block-closure (nth 4 fun))
- (lambda-closure 'lambda-closure)
- (t (if (and (symbolp (car fun))
- (or (special-form-p (car fun))
- (fboundp (car fun))))
- (car fun) :zombi)
- )))
- ((compiled-function-p fun)
- (compiled-function-name fun))
- (t :zombi))))
-
- (defun ihs-not-interpreted-env (ihs-index)
- (let ((fun (ihs-fun ihs-index)))
- (cond ((and (consp fun)
- (> ihs-index 3)
- ;(<= (ihs-vs ihs-index) (ihs-vs (- ihs-index 1)))
- )
- nil)
- (t t))))
-
- (defun set-env ()
- (setq *break-env*
- (if (ihs-not-interpreted-env *current-ihs*)
- nil
- (let ((i (ihs-vs *current-ihs*)))
- (list (vs i) (vs (1+ i)) (vs (+ i 2)))))))
-
- (defun list-delq (x l)
- (cond ((null l) nil)
- ((eq x (car l)) (cdr l))
- (t (rplacd l (list-delq x (cdr l))))))
-
- (defun super-go (i tag &aux x)
- (when (and (>= i *frs-base*) (<= i *frs-top*) (spicep (frs-tag i)))
- (if (setq x (member (frs-tag i) (vs (+ (frs-vs i) 2))
- :key #'caddr :test #'eq))
- ; Interpreted TAGBODY.
- (when (and (eq (cadar x) 'tag)
- (member tag (mapcar #'car (remove (frs-tag i) x
- :test-not #'eq
- :key #'caddr))))
- (internal-super-go (frs-tag i) tag t))
- ; Maybe, compiled cross-closure TAGBODY.
- ; But, it may also be compiled cross-closure BLOCK, in which case
- ; SUPER-GO just RETURN-FROMs with zero values.
- (internal-super-go (frs-tag i) tag nil)))
- (format *debug-io* "~s is invalid tagbody identification for ~s." i tag))
-
- (defun break-backward-search-stack (sym &aux string)
- (setq string (string sym))
- (do* ((ihs (1- *current-ihs*) (1- ihs))
- (fname (ihs-fname ihs) (ihs-fname ihs)))
- ((< ihs *ihs-base*)
- (format *debug-io* "Search for ~a failed.~%" string))
- (when (and (ihs-visible ihs)
- (search string (symbol-name fname) :test #'char-equal))
- (break-go ihs)
- (return))))
-
- (defun break-forward-search-stack (sym &aux string)
- (setq string (string sym))
- (do* ((ihs (1+ *current-ihs*) (1+ ihs))
- (fname (ihs-fname ihs) (ihs-fname ihs)))
- ((> ihs *ihs-top*)
- (format *debug-io* "Search for ~a failed.~%" string))
- (when (and (ihs-visible ihs)
- (search string (symbol-name fname) :test #'char-equal))
- (break-go ihs)
- (return))))
-
-
- (putprop :b 'simple-backtrace 'break-command)
- (putprop :r '(lambda () :resume) 'break-command)
- (putprop :resume (get :r 'break-command) 'break-command)
- (putprop :bds 'break-bds 'break-command)
- (putprop :blocks 'break-blocks 'break-command)
- (putprop :bs 'break-backward-search-stack 'break-command)
- (putprop :c 'break-current 'break-command)
- (putprop :fs 'break-forward-search-stack 'break-command)
- (putprop :functions 'break-functions 'break-command)
- (putprop :go 'break-go 'break-command)
- (putprop :h 'break-help 'break-command)
- (putprop :help 'break-help 'break-command)
- (putprop :ihs 'ihs-backtrace 'break-command)
- (putprop :env '(lambda () (describe-environment *break-env*)) 'break-command)
- (putprop :m 'break-message 'break-command)
- (putprop :n 'break-next 'break-command)
- (putprop :p 'break-previous 'break-command)
- (putprop :q 'break-quit 'break-command)
- (putprop :s 'break-backward-search-stack 'break-command)
- (putprop :vs 'break-vs 'break-command)
-
- (defun break-help ()
- (format *debug-io* "
- Break-loop Command Summary ([] indicates optional arg)
- --------------------------
-
- :bl [j] show local variables and their values, or segment of vs if compiled
- in j stack frames starting at the current one.
- :bt [n] BACKTRACE [n steps]
- :down [i] DOWN i frames (one if no i)
- :env describe ENVIRONMENT of this stack frame (for interpreted).
- :fr [n] show frame n
- :loc [i] return i'th local of this frame if its function is compiled (si::loc i)
- :r RESUME (return from the current break loop).
- :up [i] UP i frames (one if no i)
-
- Example: print a bactrace of the last 4 frames
-
- >>:bt 4
-
- Note: (use-fast-links nil) makes all non system function calls
- be recorded in the stack. (use-fast-links t) is the default
-
- Low level commands:
- ------------------
- :p [i] make current the i'th PREVIOUS frame (in list show by :b)
- :n [i] make current the i'th NEXT frame (in list show by :b)
- :go [ihs-index] make current the frame corresponding ihs-index
- :m print the last break message.
- :c show function of the current ihs frame.
- :q [i] quit to top level
- :r resume from this break loop.
- :b full backtrace of all functions and special forms.
- :bs [name] backward search for frame named 'name'
- :fs [name] search for frame named 'name'
- :vs [from] [to] Show value stack between FROM and TO
- :ihs [from] [to] Show Invocation History Stack
- :bds ['v1 'v2 ..]Show previous special bindings of v1, v2,.. or all if no v1
-
- ")
- (values)
- )
-
-
-
-